1. Technical Field
The present invention relates in general to a method and system for improving complex storage locks. More particularly, the present invention relates to a system and method for improving the performance of complex storage locks with multiple readers and writers accessing an area within a computer system.
2. Description of the Related Art
The operating system is arguably the most important program that runs on a computer. Every general-purpose computer has an operating system in order to run other programs. Operating systems perform basic tasks, such as recognizing input from the keyboard, sending output to the display screen, keeping track of files and directories, and controlling peripheral devices such as disk drives and printers.
For large systems, the operating system has even greater responsibilities and powers. It makes sure that different programs and users running at the same time do not interfere with each other. The operating system is also responsible for security, ensuring that unauthorized users do not access the system.
Operating systems can be classified as (1) multi-user which allows two or more users to run programs at the same time (some operating systems permit hundreds or even thousands of concurrent users); (2) multiprocessing which supports running a program on more than one CPU; (3) multitasking which allows more than one program to run concurrently; (4) multithreading which allows different parts of a single program to run concurrently; and (5) real time which responds to input instantly. General-purpose operating systems, such as DOS and UNIX, are typically not real-time operating systems.
Operating systems provide a software platform on top of which other programs, called application programs, can run. The application programs are usually written to run on top of a particular operating system. The choice of which operating system to use, therefore, determines to a great extent the applications that can run.
The UNIX operating system is an interactive time-sharing operating system invented in 1969. The UNIX operating system is a multi-user, multi-tasking, and multi-threaded operating system supporting serial and network connected terminals for multiple users. UNIX may also be implementing in a multiprocessing environment with two or more processors executing in the computer system. UNIX is a multitasking operating system allowing multiple users to use the same system simultaneously. The UNIX operating system includes a kernel, shell, and utilities. UNIX is a portable operating system, requiring only the kernel to be written in assembler, and supports a wide range of support tools including development, debuggers, and compilers. Variations of the UNIX operating system exist and are provided by various vendors. For example, IBM provides the AIX™ operating system that has some features and improvements not found in general UNIX operating systems.
As a multi-user operating system, UNIX allows multiple people to share the same computer system simultaneously. UNIX accomplishes this by time-slicing the computer's central processing unit, or “CPU,” into intervals. Each user gets a certain amount of time for the system to execute requested instructions. After the user's allotted time has expired, the operating system intervenes by interrupting the CPU, saving the user's program state (program code and data), restores the next user's program state and begins executing the next user's program (for the next user's amount of time). This process continues indefinitely cycling through all users using the system. When the last user's time-slice has expired, control is transferred back to the first user again and another cycle commences.
The UNIX operating system is both a multi-user operating system and a multi-tasking operating system. As the name implies, the multi-user aspect of UNIX allows multiple users to use the same system at the same time. As a multi-tasking operating system, UNIX permits multiple programs (or portions of programs called threads of execution) to execute at the same time. The operating system rapidly switches the processor between the various programs (or threads of execution) in order to execute each of the programs or threads. IBM's OS/2 and Microsoft's Windows 95/98/NT are examples of single-user multi-tasking operating systems while UNIX is an example of a multi-user multi-tasking operating system. Multi-tasking operating systems support both foreground and background tasks. A foreground task is a task that directly interfaces with the user using an input device and the screen. A background task runs in the background and does not access the input device(s) (such as the keyboard, a mouse, or a touch-pad) and does not access the screen. Background tasks include operations like printing which can be spooled for later execution.
The UNIX operating system keeps track of all programs running in the system and allocates resources, such as disks, memory, and printer queues, as required. UNIX allocates resources so that, ideally, each program receives a fair share of resources to execute properly. UNIX doles out resources using two methods: scheduling priority and system semaphores. Each program is assigned a priority level. Higher priority tasks (like reading and writing to the disk) are performed more regularly. User programs may have their priority adjusted dynamically, upwards or downwards, depending on their activity and the available system resources. System semaphores are used by the operating system to control system resources. A program can be assigned a resource by getting a semaphore by making a system call to the operating system. When the resource is no longer needed, the semaphore is returned to the operating system, which can then allocate it to another program.
Disk drives and printers are serial in nature. This means that only one request can be performed at any one time. In order for more than one user to use these resources at once, the operating system manages them using queues. Each serial device is associated with a queue. When a programs wants access to the device (i.e., a disk drive) it sends a request to the queue associated with the device. The UNIX operating system runs background tasks (called daemons), which monitor the queues and service requests for them. The requests are performed by the daemon process and the results are returned to the user's program.
Multi-tasking systems provide a set of utilities for managing processes. In UNIX, these are ps (list processes), kill (kill a process), and & at the end of a command line (run a process in the background). In UNIX, all user programs and application software use the system call interface to access system resources such as disks, printers, and memory. The system call interface in UNIX provides a set of system calls (C language functions). The purpose of the system call interface is to provide system integrity, as all low-level hardware access is under the control of the UNIX operating system and not the user-written programs. This prevents a program from corrupting the system.
Upon receiving a system call, the operating system validates its access permission, executes the request on behalf of the requesting program, and returns the results to the requesting program. If the request is invalid or the user does not have access permission, the operating system does not perform the request and an error is returned to the requesting program. The system call is accessible as a set of C language functions, as the majority of UNIX is written in the C language. Typical system calls are: _read—for reading from the disk; _write—for writing to the disk; _getch—for reading a character from a terminal; _putch—for writing a character to the terminal; and _ioctl—for controlling and setting device parameters.
As the name implies, the kernel is at the core of the UNIX operating system and is loaded each time the system is started, also referred to as a system “boot.” The kernel manages the resources of the system, presenting them to the users as a coherent system. The user does not have to understand much, if anything, about the kernel in order to use a UNIX system. The kernel provides various necessary functions in the UNIX environment. The kernel manages the system's memory and allocates it to each process. It takes time for the kernel to save and restore the program's state and switch from one program to the next (called dispatching). This action needs to execute quickly because time spent switching between programs takes away from the time available to actually run the users' programs. The time spent in the “system state” where the kernel performs tasks like switching between user programs is the system overhead and should be kept as low as possible. In a typical UNIX system, system overhead should be less than 10% of the overall time.
The kernel also schedules the work to be done by the central processing unit, or “CPU,” so that the work of each user is carried out efficiently. The kernel transfers data from one part of the system to another. Switching between user programs in main memory is also done by the kernel. Main system memory is divided into portions for the operating system and user programs. Kernel memory space is kept separate from user programs. When insufficient main memory exists to run a program, another program is written out to disk (swapped) to free enough main memory to run the first program. The kernel determines which program is the best candidate to swap out to disk based on various factors. When too many programs are being executed on the system at the same time, the system gets overloaded and the operating system spends more time swapping files out to disk and less time executing programs causing performance degradation. The kernel also accepts instructions from the “shell” and carries them out. Furthermore, the kernel enforces access permissions that are in place in the system. Access permissions exist for each file and directory in the system and determine whether other users can access, execute, or modify the given file or directory.
The fundamental structure that the UNIX operating system uses to store information is the file. A file is a sequence of bytes. UNIX keeps track of files internally by assigning each file a unique identification number. These numbers, called i-node numbers, are used only within the UNIX kernel itself. While UNIX uses i-node numbers to refer to files, it allows users to identify each file by a user-assigned name. A file name can be any sequence of characters and can be up to fourteen characters long.
Many operating systems, such as UNIX, manage shared resources, such as files, data structures, and devices, using storage locks. Storage locks prevent multiple processes from each altering a storage area at almost the same time resulting in a corrupted storage value. Storage locks include simple storage locks and complex storage locks. Simple storage locks allow one process to access the shared resource at a given time. Complex storage locks, on the other hand, allow either one writer or multiple readers to access the shared resource simultaneously. As the name implies, simple locks are generally simpler to implement and, as a result, are typically faster for shared resources that cannot benefit from the ability to support multiple simultaneous readers. Conversely, complex locks are more expensive (in terms of processing requirements) than simple locks and are slow when the number of writers is great in comparison with the number of readers. However, complex locks offer a performance advantage in situations where larger numbers of processes request to read a shared resource in comparison with the number of processes requesting to update the resource. By allowing multiple readers simultaneously, complex locks can typically dispose of large numbers of readers faster than simple locks.
A complex lock typically has three states: exclusive-write, shared-read, or unlocked. If several threads perform read operations on the resource, they first acquire the corresponding lock in shared-read mode. Since no threads are updating the resource, it is safe for all to read it. Any thread which writes to the resource first acquires the lock in exclusive-write mode. This guarantees that no other thread will read or write the resource while it is being updated.
Processes have priorities that determine their relative accessibility to a processor. When a lower priority thread owns a lock which a higher-priority thread is attempting to acquire, the owner has its priority promoted to that of the most favored thread waiting for the lock. When the owner releases the lock, its priority is restored to its normal value. Priority promotion ensures that the lock owner can run and release its lock, so that higher priority processes or threads do not remain blocked on the lock.
A linear hierarchy of locks exists. This hierarchy is imposed by software convention, but is not enforced by the system. The lockl kernel_lock variable, which is the global kernel lock, has the coarsest granularity. Other types of locks have finer granularity. The following list shows the ordering of locks based on granularity:                The kernel_lock global kernel lock;        File system locks (private to file systems);        Device driver locks (private to device drivers); and        Private fine-granularity locks.        
Locks are generally released in the reverse order from which they were acquired; all locks are released before a kernel process exits or leaves kernel mode. Kernel mode processes generally do not receive signals while they hold a lock.
Complex locks are read-write locks which protect thread-thread critical sections. Complex locks may be preemptable, meaning that a kernel thread can be preempted by another, higher priority kernel thread while it holds a complex lock. Complex locks can also be spin locks; a kernel thread which attempts to acquire a complex lock may spin (busy-wait: repeatedly execute instructions which do nothing) if the lock is not free.
Atomic operations are sequences of instructions which guarantee atomic accesses and updates of shared resources. An operation that reads a shared resource (i.e. using a complex lock in read mode) and then wishes to update the shared resource with the data that was read left intact (i.e. no intervening writers updating the resource) is an atomic operation.
One challenge with the prior art occurs when the first process wishing to write to a shared resource currently held by a set of readers is put to sleep until the shared resource is available (i.e. released by the readers currently holding the lock). When the lock is available this specific writer is woken up to request the lock in write mode. The shared resource is unavailable to other requestors during the time it takes for previous lock holders to release their read locks and the first writer to be fully woken up, acquire, and release the lock.
Another challenge is that if write request is made after a reader is woken with the expectation of sharing a lock that is already held in read mode but before the reader has acquired a read lock, the reader is put back to sleep. Awakening and suspending processes uses system resources that could otherwise be used for processing.
A final challenge occurs when a writer sets the WANT WRITE indicator in the lock due to active readers. It causes readers that are awake and ready to update the shared resource to go to sleep rather than immediately acquire the lock.
What is needed, therefore, is a system and method for improving the management of the complex lock. In particular, what is needed is a system and method to more efficiently utilize the complex lock and increase the throughput of processes desiring to use the lock.